----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    12:34:42 11/29/2014 
-- Design Name: 
-- Module Name:    decoder - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity decoder is
    Port ( instruction : in  STD_LOGIC_VECTOR (15 downto 0);
           rs1 : out  STD_LOGIC_VECTOR (3 downto 0);
           rs2 : out  STD_LOGIC_VECTOR (3 downto 0);
           rd : out  STD_LOGIC_VECTOR (3 downto 0);
           imm : out  STD_LOGIC_VECTOR (10 downto 0);
           immCode : out  STD_LOGIC_VECTOR (2 downto 0);
           aluCode : out  STD_LOGIC_VECTOR (3 downto 0);
           rm : out  STD_LOGIC;
           wm : out  STD_LOGIC;
           wb : out  STD_LOGIC;
           pc_en : out  STD_LOGIC;
			  is_branch : out STD_LOGIC;
			  imm_en : out  STD_LOGIC);
end decoder;

architecture Behavioral of decoder is
signal instr5:STD_LOGIC_VECTOR(4 downto 0);

begin
instr5<=instruction(15 downto 11);
	process(instruction)
	begin
		rs1<="1111";
		rs2<="1111";
		rd<="1111";--NB
		imm<="00000000000";
		is_branch<='0';
		case instruction(15 downto 11) is
		when "01001"=>--addiu
			rs1(2 downto 0)<=instruction(10 downto 8);
			rs1(3)<='0';
			rs2<="1111";
			rd(2 downto 0)<=instruction(10 downto 8);
			rd(3)<='0';
			aluCode<="0001";
			pc_en<='0';
			imm_en<='1';
			immCode<="011";
			imm(7 downto 0)<=instruction(7 downto 0);
			is_branch<='0';
			rm<='0';
			wm<='0';
			wb<='1';
		when "01000"=>--addiu3
			rs1(2 downto 0)<=instruction(10 downto 8);
			rs1(3)<='0';
			rs2<="1111";
			rd(2 downto 0)<=instruction(7 downto 5);
			rd(3)<='0';
			aluCode<="0001";
			pc_en<='0';
			imm_en<='1';
			immCode<="001";
			imm(3 downto 0)<=instruction(3 downto 0);
			is_branch<='0';
			rm<='0';
			wm<='0';
			wb<='1';
		when "01100"=>--addsp, bteqz, mtsp
			case instruction(10 downto 8) is
			when "011"=>--addsp
				imm(7 downto 0)<=instruction(7 downto 0);
				immCode<="011";
				rs1<="1011";--sp
				rs2<="1111";--disable
				rd<="1011";--sp
				aluCode<="0001";
				pc_en<='0';
				imm_en<='1';
				is_branch<='0';
				rm<='0';
				wm<='0';
				wb<='1';
			when "000"=>--bteqz
				rs2<="1001";--t
				rs1<="1111";
				rd<="1111";
				pc_en<='1';
				immCode<="011";
				imm_en<='1';
				imm(7 downto 0)<=instruction(7 downto 0);
				aluCode<="0001";--?
				is_branch<='1';
				rm<='0';
				wm<='0';
				wb<='0';
			when "100"=>--mtsp
				rs1<="1111";
				rs2(2 downto 0)<=instruction(7 downto 5);
				rs2(3)<='0';
				rd<="1011";
				aluCode<="0000";
				pc_en<='0';
				imm_en<='0';
				immCode<="000";
				--imm<=""
				is_branch<='0';
				rm<='0';
				wm<='0';
				wb<='1';
				when others=>
				
			end case;
		when "11100"=>--addu,subu
			case instruction(1 downto 0) is
			when "01"=>--addu
				rs1(2 downto 0)<=instruction(10 downto 8);
				rs1(3)<='0';
				rs2(2 downto 0)<=instruction(7 downto 5);
				rs2(3)<='0';
				rd(2 downto 0)<=instruction(4 downto 2);
				rd(3)<='0';
				aluCode<="0001";
				pc_en<='0';
				imm_en<='0';
				immCode<="000";
				is_branch<='0';
				rm<='0';
				wm<='0';
				wb<='1';
			when "11"=>--subu
				rs1(2 downto 0)<=instruction(10 downto 8);
				rs1(3)<='0';
				rs2(2 downto 0)<=instruction(7 downto 5);
				rs2(3)<='0';
				rd(2 downto 0)<=instruction(4 downto 2);
				rd(3)<='0';
				aluCode<="0010";
				--imm<="";
				imm_en<='0';
				immCode<="000";
				is_branch<='0';
				pc_en<='0';
				rm<='0';
				wm<='0';
				wb<='1';
			when others=>
			
			end case;
		when "11101"=>
			case instruction(4 downto 2) is
			when "000"=>
				case instruction(1 downto 0) is
				when "11"=>--sltu
					rs1(2 downto 0)<=instruction(10 downto 8);
					rs1(3)<='0';
					rs2(2 downto 0)<=instruction(7 downto 5);
					rs2(3)<='0';
					rd<="1001";
					aluCode<="0110";--< unsigned
					imm_en<='0';
					immCode<="000";
					is_branch<='0';
					pc_en<='0';
					rm<='0';
					wm<='0';
					wb<='1';
				when "00"=>
					case instruction(7 downto 5) is
					when "010"=>--mfpc
						rd(2 downto 0)<=instruction(10 downto 8);
						rd(3)<='0';
						rs1<="1111";
						rs2<="1111";
						imm_en<='1';
						immCode<="001";
						aluCode<="0001";--add
						imm(3 downto 0)<="0001";--pc+1
						pc_en<='1';
						rm<='0';
						wm<='0';
						wb<='1';
						is_branch<='0';
					when "000"=>--jr
						rs2(2 downto 0)<=instruction(10 downto 8);
						rs2(3)<='0';
						rs1<="1111";
						rd<="1111";
						aluCode<="0000";
						imm_en <= '0';
						immCode<="000";
						pc_en<='0';
						is_branch<='1';
						rm<='0';
						wm<='0';
						wb<='0';
					when others=>
					
					end case;
					
					when others=>
					
				end case;
			when "001"=>--sllv,srav
				rs2(2 downto 0)<=instruction(10 downto 8);
				rs2(3)<='0';
				rs1(2 downto 0)<=instruction(7 downto 5);
				rs1(3)<='0';
				rd(2 downto 0)<=instruction(7 downto 5);
				rd(3)<='0';
				if instruction(1 downto 0)="00" then--sllv
					aluCode<="1001";
				elsif instruction(1 downto 0)="11" then--srav
					aluCode<="1010";
				end if;
				imm_en<='0';
				immCode<="000";
				is_branch<='0';
				pc_en<='0';
				rm<='0';
				wm<='0';
				wb<='1';
			when "010"=>--cmp
				if instruction(1 downto 0) = "10" then
					rs1(2 downto 0)<=instruction(10 downto 8);
					rs1(3)<='0';
					rs2(2 downto 0)<=instruction(7 downto 5);
					rs2(3)<='0';
					rd<="1001";--T
					aluCode<="0101";--?
					immCode<="000";
					imm_en<='0';
					pc_en<='0';
					is_branch<='0';
					rm<='0';
					wm<='0';
					wb<='1';
				end if;
			when "011"=>--and, or, not
				rs1(2 downto 0)<=instruction(10 downto 8);
				rs1(3)<='0';
				rs2(2 downto 0)<=instruction(7 downto 5);
				rs2(3)<='0';
				rd(2 downto 0)<=instruction(10 downto 8);
				rd(3)<='0';
				pc_en<='0';
				--imm
				imm_en<='0';
				immCode<="000";
				is_branch<='0';
				if instruction(4 downto 0)="01100" then
					aluCode <= "0011"; --AND
				elsif instruction(4 downto 0)="01101" then
					aluCode <= "0100"; --OR
				elsif instruction(4 downto 0)="01111" then
					aluCode <= "1011"; --NOT
					rs2<="1111";
					--rd(2 downto 0)<=instruction(7 downto 5);
				end if;
				rm<='0';
				wm<='0';
				wb<='1';
			when others=>
			
			end case;
		when "00010"=>--b
			rs1<="1111";
			rs2<="1111";
			rd<="1111";
			imm<=instruction(10 downto 0);
			immcode <= "100";
			imm_en<='1';
			aluCode<="0001";--add
			pc_en<='1';
			is_branch<='1';
			rm<='0';
			wm<='0';
			wb<='0';
		when "00100"=>--beqz
			imm(7 downto 0)<=instruction(7 downto 0);
			immcode <= "011";
			imm_en<='1';
			pc_en<='1';
			is_branch<='1';
			rs2(2 downto 0)<=instruction(10 downto 8);
			rs2(3)<='0';
			rs1<="1111";
			rd<="1111";
			aluCode<="0001";--NB
			rm<='0';
			wm<='0';
			wb<='0';
		when "00101"=>--bnez
			imm(7 downto 0)<=instruction(7 downto 0);
			immcode <= "011";
			imm_en<='1';
			pc_en<='1';
			is_branch<='1';
			rs2(2 downto 0)<=instruction(10 downto 8);
			rs2(3)<='0';
			rs1<="1111";
			rd<="1111";
			aluCode<="0001";
			rm<='0';
			wm<='0';
			wb<='0';
		when "01101"=>--li
			rs1<="1111";
			rs2<="1111";
			rd(2 downto 0)<=instruction(10 downto 8);
			rd(3)<='0';
			imm(7 downto 0)<=instruction(7 downto 0);
			imm(10 downto 8)<="000";
			immCode<="100";
			imm_en<='1';
			aluCode<="0000";
			pc_en<='0';
			is_branch<='0';
			rm<='0';
			wm<='0';
			wb<='1';
		when "10011"=>--lw
			rs1(2 downto 0)<=instruction(10 downto 8);
			rs1(3)<='0';
			rs2<="1111";
			rd(2 downto 0)<=instruction(7 downto 5);
			rd(3)<='0';
			imm(4 downto 0)<=instruction(4 downto 0);
			immCode<="010";
			imm_en<='1';
			aluCode<="0001";--add
			pc_en<='0';
			is_branch<='0';
			rm<='1';
			wm<='0';
			wb<='1';
		when "10010"=>--lw_sp
			rs1<="1111";
			rs2<="1111";
			rd(2 downto 0)<=instruction(10 downto 8);
			rd(3)<='0';
			imm(7 downto 0)<=instruction(7 downto 0);
			immCode<="010";
			imm_en<='1';
			aluCode<="0001";--add
			pc_en<='0';
			is_branch<='0';
			rm<='1';
			wm<='0';
			wb<='1';
		when "11110"=>--mfih, mtih
			if instruction(7 downto 0) = "00000001" then --mtih
				rs2(2 downto 0)<=instruction(10 downto 8);
				rs2(3)<='0';
				rs1<="1111";
				rd<="1010";
				imm_en<='0';
				immCode<="000";
				aluCode<="0000";
				is_branch<='0';
				pc_en<='0';
				rm<='0';
				wm<='0';
				wb<='1';
			else--mfih NB
				rd(2 downto 0)<=instruction(10 downto 8);
				rd(3)<='0';
				rs1<="1111";
				rs2<="1010";
				imm_en<='0';
				immCode<="000";
				aluCode<="0000";
				is_branch<='0';
				pc_en<='0';
				rm<='0';
				wm<='0';
				wb<='1';
			end if;
		when "00001"=>--nop
			rs1<="1111";
			rs2<="1111";
			rd<="1111";
			aluCode<="0000";
			--imm<="";
			imm_en<='0';
			immCode<="000";
			is_branch<='0';
			pc_en<='0';
			rm<='0';
			wm<='0';
			wb<='0';
		when "00110"=>--sll, sra
			
			rd(2 downto 0)<=instruction(10 downto 8);
			rd(3)<='0';
			rs2<="1111";
			rs1(2 downto 0)<=instruction(7 downto 5);
			rs1(3)<='0';
			imm_en<='1';
			immCode<="001";--4bit, msb added
			imm(2 downto 0)<=instruction(4 downto 2);
			imm(3 downto 3)<="0";
			is_branch<='0';
			pc_en<='0';
			rm<='0';
			wm<='0';
			wb<='1';
			case instruction(1 downto 0) is
			when "00"=>--sll
				aluCode<="0111";
			when "11"=>--sra
				aluCode<="1000";
			when others=>
			
			end case;
			
		when "11011"=>--sw
			rs1(2 downto 0)<=instruction(10 downto 8);
			rs1(3)<='0';
			rs2(2 downto 0)<=instruction(7 downto 5);
			rs2(3)<='0';
			rd<="1111";--disable
			imm(4 downto 0)<=instruction(4 downto 0);
			immCode<="010";
			imm_en<='1';
			aluCode<="0001";
			pc_en<='0';
			is_branch<='0';
			rm<='0';
			wm<='1';
			wb<='0';
		when "11010"=>--sw_sp
			rs1<="1011";
			rs2(2 downto 0)<=instruction(10 downto 8);
			rs2(3)<='0';
			rd<="1111";
			aluCode<="0001";
			imm_en<='1';
			immCode<="011";
			imm(7 downto 0)<=instruction(7 downto 0);
			is_branch<='0';
			pc_en<='0';
			rm<='0';
			wm<='1';
			wb<='0';
		when "01110"=>--cmpi
			rs1(2 downto 0)<=instruction(10 downto 8);
			rs1(3)<='0';
			rs2<="1111";
			rd<="1001";--T
			aluCode<="0101";--?
			immCode<="011";
			imm_en<='1';
			imm(7 downto 0)<=instruction(7 downto 0);
			pc_en<='0';
			is_branch<='0';
			rm<='0';
			wm<='0';
			wb<='1';
		when others=>
			rs1<="1111";
			rs2<="1111";
			rd<="1111";
			aluCode<="0000";
			--imm<="";
			imm_en<='0';
			immCode<="000";
			is_branch<='0';
			pc_en<='0';
			rm<='0';
			wm<='0';
			wb<='0';
		end case;
	end process;

end Behavioral;

